home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / kali / ipx_kali.c < prev    next >
C/C++ Source or Header  |  1998-04-24  |  15KB  |  590 lines

  1. /*
  2.  * ipx_kali.c
  3.  *
  4.  * Kali compatible support for DOSEMU/LDescent IPX.
  5.  * Arne de Bruijn, 1998
  6.  */
  7.  
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <sys/types.h>
  11. #include <string.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <netdb.h>
  15. #include <stdlib.h>
  16. #include <sys/time.h>
  17. #include <errno.h>
  18. #include <unistd.h>
  19. #include <fcntl.h>
  20.  
  21. #include "ipx_ldescent.h"
  22. #include "ipx_helper.h"
  23. #include "config.h"
  24.  
  25. #include "kali_serv.h"
  26. #include "getextip.h"
  27.  
  28. extern unsigned char ipx_MyAddress[10];
  29.  
  30. struct kali_client {
  31.     int fd;
  32.     struct sockaddr_in server;
  33.     char node[6];
  34. };
  35.  
  36. static int open_sockets = 0;
  37. static int dynamic_socket = 0x401;
  38. static int pkt_seq = 0;
  39. static u_char ipx_broadcast_node[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  40. static struct kali_client *kali_client = NULL;
  41. static int last_socket = 0;
  42.  
  43. static inline void bufs_to_node(u_char *addr, u_char *port, u_char *node) {
  44. #ifdef __i386__ /* littleendian && free_alignment */
  45.     *(u_long *)(node) = ntohl(*(u_long *)addr);
  46.     *(u_short *)(node + 4) = ntohs(*(u_short *)port);
  47. #else
  48.     node[0] = addr[3]; node[1] = addr[2]; node[2] = addr[1]; node[3] = addr[0];
  49.     node[4] = port[1]; node[5] = port[0];   
  50. #endif
  51. }
  52.  
  53. static inline void node_to_bufs(u_char *node, u_char *addr, u_char *port) {
  54. #ifdef __i386__
  55.     *(u_long *)(addr) = ntohl(*(u_long *)node);
  56.     *(u_short *)(port) = ntohs(*(u_short *)(node + 4));
  57. #else
  58.     addr[0] = node[3]; addr[1] = node[2]; addr[2] = node[1]; addr[3] = node[0];
  59.     port[0] = node[5]; port[1] = node[4];   
  60. #endif
  61. }
  62.  
  63. static void addr_to_node(struct sockaddr_in *addr, u_char *node) {
  64.     bufs_to_node((u_char *)&(addr->sin_addr), (u_char *)&(addr->sin_port),
  65.      node);
  66. }
  67.  
  68. static void node_to_addr(u_char *node, struct sockaddr_in *addr) {
  69.     addr->sin_family = AF_INET;
  70.     node_to_bufs(node, (u_char *)&(addr->sin_addr.s_addr),
  71.      (u_char *)&(addr->sin_port));
  72. }
  73.  
  74. struct kali_client *kali_open(struct sockaddr_in *local) {
  75.     struct kali_client *c;
  76.     struct sockaddr_in addr;
  77.     int i;
  78.     
  79.     if (!(c = malloc(sizeof(*c))))
  80.         return NULL;
  81.     memset(c, 0, sizeof(*c));
  82.  
  83.     if ((c->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  84.         free(c);
  85.         return NULL;
  86.     }
  87.     fcntl(c->fd, F_SETFL, fcntl(c->fd, F_GETFL) | O_NONBLOCK);
  88.  
  89. /*
  90.     if (!local->sin_addr.s_addr && !local->sin_port) {
  91.         ipx_kali_GetMyAddress();
  92.         node_to_addr(ipx_MyAddress + 4, local);
  93.     }
  94. */
  95.     if ((bind(c->fd, (struct sockaddr *)local, sizeof(*local))) < 0) {
  96.         close(c->fd);
  97.         free(c);
  98.         return NULL;
  99.     }
  100.     if ((getsockname(c->fd, (struct sockaddr *)&addr, &i)) < 0) {
  101.         close(c->fd);
  102.         free(c);
  103.         return NULL;
  104.     }
  105.  
  106.     addr_to_node(&addr, c->node);
  107.  
  108.     return c;
  109. }
  110.  
  111. static void tv_add(struct timeval *tv, long sec, long usec) {
  112.     if ((tv->tv_usec += usec) >= 1000000) {
  113.         tv->tv_usec -= 1000000;
  114.         sec++;
  115.     }
  116.     if (tv->tv_usec < 0) {
  117.         tv->tv_usec += 1000000;
  118.         sec--;
  119.     }
  120.     tv->tv_sec += sec;
  121. }
  122.  
  123. int kali_send_recv(struct kali_client *c,
  124.  char *sendbuf, int sendlen, char *recvbuf, int recvlen, int *gotlen) {
  125.     struct sockaddr_in addr;
  126.     int i;
  127.     fd_set rec;
  128.     struct timeval tvtemp, tvend, tv;
  129.     
  130.     if (gotlen) *gotlen = 0;
  131.     FD_ZERO(&rec);
  132.     FD_SET(c->fd, &rec);
  133.     gettimeofday(&tvend, NULL);
  134.     tv_add(&tvend, 10, 0); /* timeout: 10 sec */
  135.     
  136.     while (1) {
  137.         while (sendto(c->fd, sendbuf, sendlen, 0, (struct sockaddr *)&c->server, 
  138.          sizeof(c->server)) < 0) {
  139.             if (errno == EINTR)
  140.                 continue;
  141.             return -1;
  142.         }
  143.         gettimeofday(&tv, NULL);
  144.         tvtemp = tvend;
  145.         tv_add(&tvtemp, -tv.tv_sec, -tv.tv_usec);
  146.         if (tvtemp.tv_sec < 0) {
  147.             errno = ETIMEDOUT;
  148.             return -1;
  149.         }
  150.         tv.tv_sec = 1;
  151.         tv.tv_usec = 0;
  152.         while ((i = select(c->fd + 1, &rec, NULL, NULL, &tv)) < 0) {
  153.             if (errno == EINTR)
  154.                 continue;
  155.             return -1;
  156.         }
  157.         if (i == 0) n_printf("IPX_kali: kali_send_recv() timeout\n");
  158.         if (i > 0) {
  159.             i = sizeof(addr);
  160.             while ((i = recvfrom(c->fd, recvbuf, recvlen, 0, 
  161.              (struct sockaddr *)&addr, &i)) < 0) {
  162.                 if (errno == EINTR)
  163.                     continue;
  164.                 return -1;
  165.             }
  166. #if 1 /* verbose */
  167.             if ((addr.sin_addr.s_addr != c->server.sin_addr.s_addr) ||
  168.                 (addr.sin_port != c->server.sin_port)) {
  169.                 n_printf("IPX_kali: (connect) recv invalid address %s:%d\n",
  170.                  inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  171.                 continue;
  172.             }
  173.             if ((i <= 4) || (memcmp(recvbuf, "KALI", 4))) {
  174.                 n_printf("IPX_kali: (connect) recv invalid header "
  175.                  "%c%c%c%c (%d)\n",
  176.                  recvbuf[0], recvbuf[1], recvbuf[2], recvbuf[3], i);
  177.                 continue;
  178.             }
  179.             if (recvbuf[4] == '6') {
  180.                 n_printf("IPX_kali: KALI6 in send_recv\n");
  181.                 continue;
  182.             }
  183. #else
  184.             if ((addr.sin_addr.s_addr == c->server.sin_addr.s_addr) &&
  185.                 (addr.sin_port == c->server.sin_port) &&
  186.                 (i > 4) &&
  187.                 (!strncmp(recvbuf, "KALI", 4) &&
  188.                 (recvbuf[4] != '6'))
  189. #endif              
  190.                 if (gotlen) *gotlen = i;
  191.                 return 0;
  192.         }
  193.     }
  194. }
  195.  
  196. int kali_recv(struct kali_client *c, char *buf, int buflen, int *reclen,
  197.  char *node) {
  198.     int i;
  199.     struct sockaddr_in addr;
  200.     
  201.     if (reclen) *reclen = 0;
  202.     i = sizeof(addr);
  203.     if ((i = recvfrom(c->fd, buf, buflen, 0, 
  204.      (struct sockaddr *)&addr, &i)) < 0)
  205.         return -1;
  206.     if (reclen) *reclen = i;
  207.     if (node) addr_to_node(&addr, node);
  208.     return 0;
  209. }
  210.  
  211. int kali_connect(struct kali_client *c,
  212.  struct sockaddr_in *server) {
  213.     char buf[342];
  214.     char resp[128];
  215.     int resplen;
  216. /*
  217.     struct hostent *h;
  218.     struct sockaddr_in addr;
  219. */
  220.     
  221.     memcpy(&c->server, server, sizeof(*server));
  222.     memset(buf, 0, 342);
  223.     strcpy(buf, "KALI1");
  224.     strcpy(buf+0x05, "ld_"); /* FIXME: get real kali name */
  225.     strcpy(buf+0x08, config_last_player);
  226.     strcpy(buf+0x1b, "1.2xs");
  227. /*
  228.     strcpy(buf+0x2d, "<email>");
  229.     strcpy(buf+0x78, "<fullname>");
  230.     strcpy(buf+0x11a, "<location>");
  231. */
  232. /*
  233.     node_to_addr(ipx_MyAddress + 4, &addr);
  234.     if ((h = gethostbyaddr((char *)&addr.sin_addr.s_addr, 4, AF_INET))) {
  235.         strncpy(buf+0x12e, h->h_name, 39);
  236.     }
  237. */
  238.  
  239.     n_printf("IPX_kali: connecting to server...\n");
  240.     if (kali_send_recv(c, buf, 342, resp, 128, &resplen) < 0)
  241.         return -1;
  242.     if (resp[4] == '5') {
  243.         resp[resplen - 1] = 0;
  244.         n_printf("IPX_kali: connection refused: \"%s\"\n", resp + 5);
  245.         return -1;
  246.     }
  247.     if (/*(resplen != 11) ||*/ (resp[4] != '2')) {
  248.         n_printf("IPX_kali: invalid connect response %c%c%c%c%c (%d)\n",
  249.          resp[0], resp[1], resp[2], resp[3], resp[4], resplen);
  250.         return -1;
  251.     }
  252.     bufs_to_node(resp + 5, resp + 9, c->node);
  253.     return 0;    
  254. }
  255.  
  256. int kali_send_server(struct kali_client *c, char *buf, int buflen) {
  257.     return sendto(c->fd, buf, buflen, 0,
  258.      (struct sockaddr *)&c->server, sizeof(c->server));
  259. }
  260.  
  261. int kali_disconnect(struct kali_client *c) {
  262.     char buf[5], recvbuf[5];
  263.  
  264.     memcpy(buf, "KALI3", 5);
  265.     if (kali_send_recv(c, buf, 5, recvbuf, 5, NULL) < 0) {
  266.         n_printf("IPX_kali: error %d sending close\n", errno);
  267.         return -1;
  268.     }
  269.     if (recvbuf[4] != '4') {
  270.         n_printf("IPX_kali: (disconnect) recv invalid pkt: %c\n", recvbuf[4]);
  271.         return -1;
  272.     }
  273.  
  274.     return 0;
  275. }
  276.  
  277. int kali_close(struct kali_client *c) {
  278.     close(c->fd);
  279.     free(c);
  280.     return 0;
  281. }
  282.  
  283. static int get_server_addr(struct sockaddr_in *addr) {
  284.     char *p, server[SERVER_NAME_LEN];
  285.  
  286.     addr->sin_family = AF_INET;
  287.     if ((p = strchr(config_kali_server, ':'))) {
  288.         addr->sin_port = htons(atol(p + 1));
  289.         strncpy(server, config_kali_server, p - config_kali_server);
  290.         server[p - config_kali_server] = 0;
  291.         p = server;
  292.     } else {
  293.         addr->sin_port = htons(2213);
  294.         p = config_kali_server;
  295.     }
  296.     if (!strchr(p, '.') || !inet_aton(p, &addr->sin_addr)) {
  297.         n_printf("IPX_kali: invalid server address\n");
  298.         return -1;
  299.     }
  300.     return 0;
  301. }
  302.  
  303. int ipx_kali_GetMyAddress(void) {
  304.     int i;
  305.     int s;
  306.     struct sockaddr_in addr;
  307.     unsigned char empty_address[10];
  308.     
  309.     memset(empty_address, 0, sizeof(empty_address));
  310.     if (memcmp(ipx_MyAddress, empty_address, 10))
  311.         return 0;
  312.  
  313.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  314.         n_printf("IPX_kali: (getaddr) error opening socket\n");
  315.         return -1;
  316.     }
  317.     addr.sin_family = AF_INET;
  318.     addr.sin_addr.s_addr = 0;
  319.     addr.sin_port = htons(2213);
  320.     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  321.         n_printf("IPX_kali: (getaddr) error %d binding to 2213\n", errno);
  322.         close(s);
  323.         return -1;
  324.     }
  325.     if (get_server_addr(&addr) < 0) {
  326. #ifdef NO_SERVER
  327.         return -1;
  328.     }
  329. #else
  330.         if (get_external_ip(&addr.sin_addr) < 0)
  331.             return -1;
  332.     } else {
  333. #endif  
  334.     while (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  335.         if (errno == EINTR)
  336.             continue;
  337.         n_printf("IPX_kali: (getaddr) error %d in connect()\n", errno);
  338.         close(s);
  339.         return -1;
  340.     }
  341.     i = sizeof(addr);
  342.     if (getsockname(s, (struct sockaddr *)&addr, &i) < 0) {
  343.         n_printf("IPX_kali: (getaddr) error %d in getscokname()\n", errno);
  344.         close(s);
  345.         return -1;
  346.     }
  347. #ifndef NO_SERVER
  348.     }
  349. #endif  
  350.     close(s);
  351.     memset(ipx_MyAddress, 0, 4);
  352.     addr_to_node(&addr, ipx_MyAddress + 4);
  353.     return 0;
  354. }
  355.  
  356. int ipx_kali_OpenSocket(ipx_socket_t *sk, int port) {
  357.     struct sockaddr_in local, server;
  358.     int i;
  359.  
  360.     if (!open_sockets) {
  361.         if (kali_client) {
  362.             kali_disconnect(kali_client);
  363.             kali_close(kali_client);
  364.             kali_client = NULL;
  365.         }
  366.         for (i = 0; i < 10 && !ipx_MyAddress[i]; i++) ;
  367.         if (i == 10)
  368.             ipx_kali_GetMyAddress();
  369.         node_to_addr(ipx_MyAddress + 4, &local);
  370.         n_printf("local: %s\n", inet_ntoa(local.sin_addr));
  371.         if (!(kali_client = kali_open(&local))) {
  372.             n_printf("IPX_kali: error connecting to server\n");
  373.             return -1;
  374.         }
  375.         if (!get_server_addr(&server))
  376.             if (kali_connect(kali_client, &server) < 0) {
  377.                 n_printf("IPX_kali: kali_connect failed (%d)\n", errno);
  378.                 kali_close(kali_client);
  379.                 kali_client = NULL;
  380.                 return -1;
  381.             }
  382.     }
  383.     open_sockets++;
  384.     if (!port)
  385.         port = dynamic_socket++;
  386.     last_socket = port;
  387.     sk->fd = kali_client->fd;
  388.     sk->socket = port;
  389.     return 0;
  390. }
  391.  
  392. void ipx_kali_CloseSocket(ipx_socket_t *mysock) {
  393.     if (!open_sockets) {
  394.         n_printf("IPX_kali: close w/o open\n");
  395.         return;
  396.     }
  397.     if (--open_sockets) {
  398.         n_printf("IPX_kali: (closesocket) %d sockets left\n", open_sockets);
  399.         return;
  400.     }
  401.     if (kali_client) {
  402.         if (kali_client->server.sin_port)
  403.             if (kali_disconnect(kali_client) < 0)
  404.                 n_printf("IPX_kali: (closesocket) error disconnecting\n");
  405.         kali_close(kali_client);
  406.         kali_client = NULL;
  407.     }
  408. }
  409.  
  410. int ipx_kali_SendPacket(ipx_socket_t *mysock, IPXPacket_t *IPXHeader,
  411.  u_char *data, int dataLen) {
  412.     struct sockaddr_in *addr, destaddr;
  413.     char newdata[MAX_PACKET_DATA + 14];
  414.     int i;
  415.  
  416.     if (!kali_client)
  417.         return -1;
  418.     memcpy(newdata, "KALIB", 5);
  419.     addr = &kali_client->server;
  420.     if (memcmp(IPXHeader->Destination.Node, ipx_broadcast_node, 6)) {
  421.         newdata[4] = '0';
  422.         node_to_addr(IPXHeader->Destination.Node, &destaddr);
  423.         addr = &destaddr;
  424.     }
  425.     newdata[5] = pkt_seq & 255;
  426.     newdata[6] = pkt_seq >> 8;
  427.     newdata[7] = 0x80; /* ? */
  428.     newdata[8] = 0x00; /* ? */
  429.     memcpy(newdata + 9, IPXHeader->Destination.Socket, 2);
  430.     memcpy(newdata + 11, IPXHeader->Source.Socket, 2);
  431.     memcpy(newdata + 13, data, dataLen);
  432.     pkt_seq++;
  433.  
  434.     if (!addr->sin_port) {
  435.         struct sockaddr_in laddr;
  436.         node_to_addr(kali_client->node, &laddr);
  437.         kali_server_bcast(mysock->fd, newdata + 5, dataLen + 8, &laddr);
  438.     }
  439.         
  440.     while ((i = sendto(mysock->fd, newdata, dataLen + 13, 0,
  441.          (struct sockaddr *)addr, sizeof(*addr))) < 0) {
  442.         if (errno == EINTR)
  443.             continue;
  444.         return -1;
  445.     }
  446.     return (i < 13) ? 0 : i - 13;
  447. }
  448.  
  449. static int kali0_to_ipx(char *buf, int size, 
  450.  char *outbuf, int outbufsize, struct ipx_recv_data *rd) {
  451.     if ((size -= 8) < 0)
  452.         n_printf("IPX_kali: KALI0 too small\n");
  453.     else {
  454.         memcpy(&rd->dst_socket, buf + 4, 2);
  455.         memcpy(&rd->src_socket, buf + 6, 2);
  456.         if (size > outbufsize) size = outbufsize;
  457.         memcpy(outbuf, buf + 8, size);
  458.         return size;
  459.     }
  460.     return -1;
  461. }
  462.  
  463. static int decomp(unsigned char *outbuf, int outbufsize, unsigned char *buf, 
  464.  int size) {
  465.     int i;
  466.     unsigned char *p = outbuf, c;
  467.  
  468.     if (!outbufsize) return 0;
  469.     while (size--) {
  470.         if ((((*p = *(buf++)) + 1) & 0xfe) != 0xfe) {
  471.             p++;
  472.             if (!(--outbufsize))
  473.                 break;
  474.             continue;
  475.         }
  476.         if (*p == 0xfd) {
  477.             i = (outbufsize >= 3) ? 3 : outbufsize;
  478.             c = 0;
  479.         } else {
  480.             if ((size -= 2) < 0)
  481.                 return -1;
  482.             if (outbufsize < (i = *(buf++)))
  483.                 i = outbufsize; 
  484.             c = *(buf++);
  485.         }
  486.         memset(p, c, i);
  487.         p += i;
  488.         if (!(outbufsize -= i))
  489.             break;
  490.     }
  491.     return (p - outbuf);
  492. }
  493.  
  494. static int kaliext_to_ipx(unsigned char *buf, int size, 
  495.  unsigned char *outbuf, int outbufsize, struct ipx_recv_data *rd) {
  496.     unsigned char *p;
  497.     int i;
  498.     
  499.     if ((size -= 6) < 0)
  500.         n_printf("IPX_kali: KALIext too small\n");
  501.     else {
  502.         memcpy(&rd->dst_socket, buf + 1, 2);
  503.         memcpy(&rd->src_socket, buf + 3, 2);
  504.         p = buf + 6;
  505.         if (!(i = buf[5]) && (size)) {
  506.             i = buf[6] + (buf[7] << 8);
  507.             p += 2;
  508.             size -= 2;
  509.         }
  510.         if (i > outbufsize) i = outbufsize;
  511.         if (buf[0] & 0x80)
  512.             i = decomp(outbuf, i, p, size);
  513.         else {
  514.             if (i > size) i = size;
  515.             memcpy(outbuf, p, i);
  516.         }
  517.         return i;
  518.     }
  519.     return -1;
  520. }
  521.  
  522. int ipx_kali_ReceivePacket(ipx_socket_t *s, char *outbuf, int outbufsize, 
  523.  struct ipx_recv_data *rd) {
  524.     char buf[MAX_PACKET_DATA + 30];
  525.     int i, size;
  526.     struct sockaddr_in addr;
  527.     int allowpkt = 16;
  528.  
  529.     if (!kali_client)
  530.         return -1;
  531.     while (allowpkt--) {
  532.         i = sizeof(addr);
  533.         while ((size = recvfrom(kali_client->fd, buf, MAX_PACKET_DATA + 30, 0,
  534.              (struct sockaddr *) &addr, &i)) < 0) {
  535.             if (errno == EINTR)
  536.                 continue;
  537.             return -1;
  538.         }
  539.         /*  n_printf("IPX_kali: received %c%c%c%c%c, %d from %s:%d\n",
  540.          buf[0], buf[1], buf[2], buf[3], buf[4], size, inet_ntoa(addr.sin_addr),
  541.          ntohs(addr.sin_port));*/
  542.         memset(rd->src_network, 0, 4);
  543.         rd->pkt_type = 0;
  544.         if ((size < 5) || (memcmp(buf, "KALI", 4))) {
  545.             addr_to_node(&addr, rd->src_node);
  546.             return kaliext_to_ipx(buf, size, outbuf, outbufsize, rd);
  547.         }
  548.         switch (buf[4]) {
  549.             case '0':
  550.                 addr_to_node(&addr, rd->src_node);
  551.                 return kali0_to_ipx(buf + 5, size - 5, outbuf, outbufsize, rd);
  552.             case 'P':
  553.                 if (size < 11)
  554.                     n_printf("IPX_kali: KALIP too small (%d)\n", size);
  555.                 else {
  556.                     bufs_to_node(buf + 5, buf + 9, rd->src_node);
  557.                     if ((size >= 16) && (!strncmp(buf + 11, "KALI0", 5))) {
  558.                         return kali0_to_ipx(buf + 16, size - 16, 
  559.                          outbuf, outbufsize, rd);
  560.                     } else
  561.                         return kaliext_to_ipx(buf + 11, size - 11, 
  562.                          outbuf, outbufsize, rd);
  563.                 }
  564.                 continue; /*break;*/
  565.             case '6':
  566.                 memcpy(buf, "KALIALinux\0\0\0\0", 14);
  567.                 buf[18] = last_socket >> 8;
  568.                 buf[19] = last_socket & 255;
  569.                 kali_send_server(kali_client, buf, 20);
  570.                 continue; /*break;*/
  571.             case '1':
  572.                 kali_server_add(kali_client->fd, buf + 5, size - 5, &addr);
  573.                 continue;
  574.             case '3':
  575.                 kali_server_close(kali_client->fd, buf + 5, size - 5, &addr);
  576.                 continue;
  577.             case 'B':
  578.                 kali_server_bcast(kali_client->fd, buf + 5, size - 5, &addr);
  579.                 addr_to_node(&addr, rd->src_node);
  580.                 return kali0_to_ipx(buf + 5, size - 5, outbuf, outbufsize, rd);
  581.             case 'M':
  582.                 kali_server_msg(kali_client->fd, buf + 5, size - 5, &addr);
  583.                 continue;
  584.             default:
  585.                 n_printf("IPX_kali: unknown pkt KALI%c\n", buf[4]);
  586.         }
  587.     }
  588.     return -1;
  589. }
  590.